/*
 * Copyright 2008 Andrej Herich
 * 
 * http://azetclient.yw.sk/
 * http://azetclient.googlecode.com/
 * 
 * This file is part of AzetClient.
 * 
 * AzetClient is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * AzetClient is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with AzetClient.  If not, see <http://www.gnu.org/licenses/>.
 */

package sk.yw.azetclient.gui;

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.util.Arrays;
import java.util.Locale;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
import sk.yw.azetclient.Main;
import sk.yw.azetclient.gui.actions.AboutAction;
import sk.yw.azetclient.gui.actions.ExitAction;
import sk.yw.azetclient.managers.BuddyListManager;
import sk.yw.azetclient.managers.ConnectionManager;
import sk.yw.azetclient.managers.ConnectionManagerEvent;
import sk.yw.azetclient.managers.ConnectionManagerListener;
import sk.yw.azetclient.managers.MessageThreadManager;
import sk.yw.azetclient.model.Buddy;
import sk.yw.azetclient.model.Message;
import sk.yw.azetclient.model.MessageThread;

/**
 *
 * @author  error216
 */
public class MainFrame extends javax.swing.JFrame
        implements ConnectionManagerListener{
    
    private static final long serialVersionUID = 349386444l;
    
    private static final Logger logger = Logger.getLogger(MainFrame.class);
    
    private AuthenticationDialog authenticationDialog;
    
    private BuddyListManager buddyListManager;
    private ConnectionManager connectionManager;
    private MessageThreadManager messageThreadManager;
    
    private BuddyListModel buddyListModel = new BuddyListModel();
    private boolean trayIconEnabled = false;
    
    private ChangeMainFrameVisibilityMenuItem changeMainFrameVisibility;
    
    private ConversationManager conversationManager;
    private ConversationFocusQueue conversationFocusQueue = new ConversationFocusQueue();
    
    /** Creates new form MainFrame */
    public MainFrame() {
        logger.info("Creating main frame.");
        
        initComponents();
        
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int x = Math.max(0, screenSize.width - getSize().width);
        int y = Math.max(0, (screenSize.height - getSize().height) / 2);
        setLocation(x, y);
        
        logger.info("Main frame created.");
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        buddyList = new javax.swing.JList();
        jMenuBar1 = new javax.swing.JMenuBar();
        programMenu = new javax.swing.JMenu();
        jMenuItem2 = new javax.swing.JMenuItem();
        helpMenu = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle(Main.APPLICATION_NAME + " " + Main.VERSION);
        setIconImage((new ImageIcon(this.getClass().getClassLoader().getResource("sk/yw/azetclient/img/icon.png"))).getImage());
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                MainFrame.this.windowClosing(evt);
            }
        });

        buddyList.setModel(buddyListModel);
        buddyList.setCellRenderer(new BuddyCellRenderer());
        buddyList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                buddyListMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(buddyList);

        programMenu.setText(Main.getText("menu.program"));

        jMenuItem2.setAction(new ExitAction());
        programMenu.add(jMenuItem2);

        jMenuBar1.add(programMenu);

        helpMenu.setText(Main.getText("menu.help"));

        jMenuItem1.setAction(new AboutAction());
        helpMenu.add(jMenuItem1);

        jMenuBar1.add(helpMenu);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 270, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 588, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void windowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_windowClosing
        if (trayIconEnabled) {
            setVisible(false);
            repaint();
        } else {
            (new ExitAction()).actionPerformed(null);
        }
}//GEN-LAST:event_windowClosing

    private void buddyListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buddyListMouseClicked
        if (evt.getSource().equals(buddyList) && evt.getClickCount() == 2) {
            Buddy buddy = (Buddy) buddyList.getSelectedValue();
            MessageThread thread = messageThreadManager.createNewThread();
            conversationManager.createThreadPanel(buddy, thread, true);
        }
    }//GEN-LAST:event_buddyListMouseClicked
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JList buddyList;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JMenu programMenu;
    // End of variables declaration//GEN-END:variables
    
    public void start() {
        if (SystemTray.isSupported()) {
            logger.info("System tray is supported.");
            try {
                createTrayIcon();
                trayIconEnabled = true;
            } catch (Throwable throwable) {
                logger.error("Unable to create tray icon.", throwable);
            }
        } else {
            logger.info("System tray is not supported.");
        }
        
        if ("true".equals(
                Main.getProperty("azetclient.automaticAuthentication"))) {
            authenticate(Main.getProperty("azetclient.username"),
                    Main.getProperty("azetclient.password"));
        } else {
            authenticationDialog = new AuthenticationDialog(this, true);
            authenticationDialog.setVisible(true);
        }
    }
    
    private void createTrayIcon() throws AWTException {
        final PopupMenu popupMenu = new PopupMenu();
        final TrayIcon trayIcon = new TrayIcon(getIconImage());
        final SystemTray tray = SystemTray.getSystemTray();
        
        changeMainFrameVisibility =
                new ChangeMainFrameVisibilityMenuItem(isVisible());
        addWindowListener(changeMainFrameVisibility);
        popupMenu.add(changeMainFrameVisibility);
        trayIcon.addActionListener(changeMainFrameVisibility);
        
        ExitAction exitAction = new ExitAction();
        String exitActionName =
                (String) exitAction.getValue(AbstractAction.NAME);
        MenuItem exitItem = new MenuItem(exitActionName);
        exitItem.addActionListener(exitAction);
        popupMenu.add(exitItem);
        
        trayIcon.setImageAutoSize(true);
        trayIcon.setPopupMenu(popupMenu);
        tray.add(trayIcon);
    }
    
    public void authenticate(String username, final String password) {
        final Buddy user = new Buddy();
        user.setName(username);
        
        String storageDir = Main.CONFIG_DIR
                + System.getProperty("file.separator")
                + Main.getProperty("azetclient.messageThreadStorage.dir")
                + System.getProperty("file.separator")
                + username.toLowerCase(Locale.ENGLISH);
        
        buddyListManager = new BuddyListManager();
        
        messageThreadManager = new MessageThreadManager(user, storageDir,
                Integer.valueOf(
                Main.getProperty("azetclient.messageThreadStorage.interval")));
        
        connectionManager = new ConnectionManager(buddyListManager,
                messageThreadManager, 
                Integer.valueOf(
                Main.getProperty("azetclient.buddyList.interval")),
                Integer.valueOf(
                Main.getProperty("azetclient.message.interval")));
        connectionManager.addConnectionManagerListener(this);
        
        conversationManager = new ConversationManager(user);
        messageThreadManager.addMessageThreadManagerListener(
                conversationManager);
        
        (new Thread() {
            @Override
            public void run() {
                connectionManager.authenticate(user, password);
            }
        }).start();
    }
    
    public void stop() {
        messageThreadManager.cancelAll();
        messageThreadManager.storeThreads();
        
        connectionManager.cancelAll();
        connectionManager.disconnect();
    }

    public void errorOccured(ConnectionManagerEvent event) {
        final javax.swing.JFrame frame = this;
        final Throwable error = (Throwable) event.getSubject();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(frame,
                        error + "\n" + Arrays.toString(error.getStackTrace()),
                        Main.getText("error"),
                        JOptionPane.ERROR_MESSAGE);
            }
        });
    }

    public void authenticationSucceeded(ConnectionManagerEvent event) {
        buddyListModel.initialAdd(buddyListManager.getBuddies());
        buddyListManager.addBuddyListManagerListener(buddyListModel);
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                if (authenticationDialog != null) {
                    authenticationDialog.dispose();
                }
            }
        });
    }

    public void authenticationFailed(ConnectionManagerEvent event) {
        final javax.swing.JFrame frame = this;
        if (authenticationDialog == null) {
            SwingUtilities.invokeLater(new Runnable(){
                public void run() {
                    authenticationDialog =
                            new AuthenticationDialog(frame, true);
                    authenticationDialog.setFieldsEnabled(false);
                    authenticationDialog.setVisible(true);
                }
            });
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(authenticationDialog,
                        Main.getText("authenticationFailed.message"),
                        Main.getText("authenticationFailed.title"),
                        JOptionPane.WARNING_MESSAGE);
                authenticationDialog.setFieldsEnabled(true);
            }
        });
        
    }

    public void messageNotSent(ConnectionManagerEvent event) {
        
    }

    public ConversationFocusQueue getConversationFocusQueue() {
        return conversationFocusQueue;
    }
    
    public void sendMessage(Message message) {
        connectionManager.sendMessage(message);
    }
}
